#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef _WIN32
#include <windows.h>
#include <windowsx.h>
#else
#include <sys/time.h>
#include <time.h>
#include "unistd.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "pthread.h"

#include "BList.h"
#include "BVector.h"
#include "geometrics.h"
#include "quaternion.h"
#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "randomc.h"

#include "AWEntity.h"
#include "AWMessage.h"
#include "AWBrain.h"
#include "AWTracerBrain.h"
#include "AWThreadedBrain.h"
#include "AWNOOSBrain.h"
#include "AWNOOSExperimenterBrainCV.h"
#include "AWNOOSExperimenterBrainCVContinuous.h"

#include "CaseBaseUtils.h"

#include "loader.h"

AW_NOOSExperimenterBrainCVContinuous::AW_NOOSExperimenterBrainCVContinuous(Ontology *O,FTKBase *Memory,FTKBase *CB,bool pause) : AW_NOOSBrain(O,Memory,CB,pause) 
{
	class_name->set("AW_NOOSExperimenterBrainCVContinuous");

	m_n_folds=10;
	m_n_iterations=5;
	m_percentage_of_external_testset=0.1F;
	m_percentage_to_distribute_as_initial_training=0.1F;
	m_times_to_send_external_testset=11;
	m_desired_bias = 0.0f;
	m_problem_sort=new Symbol("sponge-problem");

	m_collaboration_strategy=new Symbol();
	m_test_collaboration_strategy=new Symbol();

	m_random=new TRanrotBGenerator(0);

} /* AW_NOOSExperimenterBrainCVContinuous::AW_NOOSExperimenterBrainCVContinuous */ 



AW_NOOSExperimenterBrainCVContinuous::AW_NOOSExperimenterBrainCVContinuous(FILE *fp,Ontology *O,FTKBase *Memory,FTKBase *CB,bool pause) : AW_NOOSBrain(O,Memory,CB,pause) 
{
	class_name->set("AW_NOOSExperimenterBrainCVContinuous");

	m_n_folds=10;
	m_n_iterations=5;
	m_percentage_of_external_testset=0.1F;
	m_percentage_to_distribute_as_initial_training=0.1F;
	m_times_to_send_external_testset=11;
	m_desired_bias = 0.0f;
	m_problem_sort=new Symbol("sponge-problem");

	m_collaboration_strategy=new Symbol();
	m_test_collaboration_strategy=new Symbol();
	
	m_random=new TRanrotBGenerator(0);

	load(fp);
} /* AW_NOOSExperimenterBrainCVContinuous::AW_NOOSExperimenterBrainCVContinuous */ 


AW_NOOSExperimenterBrainCVContinuous::~AW_NOOSExperimenterBrainCVContinuous()
{

	if (m_collaboration_strategy!=0) delete m_collaboration_strategy;
	m_collaboration_strategy=0;
	if (m_test_collaboration_strategy!=0) delete m_test_collaboration_strategy;
	m_test_collaboration_strategy=0;

	if (m_problem_sort==0) delete m_problem_sort;
	m_problem_sort=0;

} /* AW_NOOSExperimenterBrainCVContinuous::~AW_NOOSExperimenterBrainCVContinuous */ 


bool AW_NOOSExperimenterBrainCVContinuous::load(FILE *fp) 
{
	if (!AW_NOOSBrain::load(fp)) return false;

	if (2!=fscanf(fp,"%i %i",&m_n_folds,&m_n_iterations)) return false;
	if (4!=fscanf(fp,"%f %f %i %f",&m_percentage_of_external_testset,&m_percentage_to_distribute_as_initial_training,&m_times_to_send_external_testset,&m_desired_bias)) return false;

	if (m_problem_sort==0) delete m_problem_sort;
	m_problem_sort=new Symbol(fp);

	if (m_collaboration_strategy==0) delete m_collaboration_strategy;
	m_collaboration_strategy=new Symbol(fp);

	if (m_test_collaboration_strategy==0) delete m_test_collaboration_strategy;
	m_test_collaboration_strategy=new Symbol(fp);


	return true;
} /* AW_NOOSExperimenterBrainCVContinuous::load */ 


bool AW_NOOSExperimenterBrainCVContinuous::save(FILE *fp) 
{
	if (!AW_NOOSBrain::save(fp)) return false;

	fprintf(fp,"%i %i\n",m_n_folds,m_n_iterations);
	fprintf(fp,"%g %g %i %g\n",m_percentage_of_external_testset,m_percentage_to_distribute_as_initial_training,m_times_to_send_external_testset,m_desired_bias);
	m_problem_sort->save(fp);
	m_collaboration_strategy->save(fp);
	m_test_collaboration_strategy->save(fp);

	return true;
} /* AW_NOOSExperimenterBrainCVContinuous::save */ 


bool AW_NOOSExperimenterBrainCVContinuous::is_a(char *c)
{
	if (strcmp(c,"AW_NOOSExperimenterBrainCVContinuous")==0) return true;

	return AW_NOOSBrain::is_a(c);
} /* AW_NOOSExperimenterBrainCVContinuous::is_a */ 


bool AW_NOOSExperimenterBrainCVContinuous::is_a(Symbol *c)
{
	if (c->cmp("AW_NOOSExperimenterBrainCVContinuous")) return true;

	return AW_NOOSBrain::is_a(c);
} /* AW_NOOSExperimenterBrainCVContinuous::is_a */ 


void AW_NOOSExperimenterBrainCVContinuous::thread(void)
{
	List<Symbol> agent_names,monitor_names;
	Symbol *agent_name;
	List<FeatureTerm> case_base;
	List<char> case_base_text;	/* cases converted to NOOS */ 
	List<FeatureTerm> *folds;
	List<FeatureTerm> training_set,test_set;
	FeatureTerm *f;
	int iteration,fold;
	int *total_correct_answers;
	int *total_incorrect_answers;
	int *average_cb_size;
	int initial_time;

	List<float> values_for_excel;

	{
		int i;
		total_correct_answers=new int[m_times_to_send_external_testset];
		total_incorrect_answers=new int[m_times_to_send_external_testset];
		average_cb_size=new int[m_times_to_send_external_testset];
		for(i=0;i<m_times_to_send_external_testset;i++) {
			total_correct_answers[i]=0;
			total_incorrect_answers[i]=0;
			average_cb_size[i]=0;
		} /* for */ 
	}

	folds=new List<FeatureTerm>[m_n_folds];

	/* Get the data set: */ 
	test_status();
	{
		char *s;
		FeatureTerm *c;
		List<FeatureTerm> *l;
		l=m_casebase->SearchFT(m_ontology->get_sort(m_problem_sort->get()));

		while(!l->EmptyP()) {
			c=l->ExtractIni();
			s=c->toStringNOOS(m_memory);
			case_base.Add(new FeatureTerm(c));
			case_base_text.Add(s);
		} /* while */  
		delete l;
	}
	write_debug_report("[Sync]: working with %i '%s' cases.\n",case_base.Length(),m_problem_sort->get());

	test_status();
	initial_time=GetTickCount();
	write_debug_report("[Sync]: starting experiments...\n");
	do {
		/* Get other agent's names: */ 
		test_status();
		pthread_mutex_lock(&m_sensor_data_mutex);
		m_sensor_data.Rewind();
		while(m_sensor_data.Iterate(f)) {						
			if (f->getSort()->is_a(m_ontology->get_sort("sensed-agent")) &&
				!f->getSort()->is_a(m_ontology->get_sort("sensed-self"))) {
				Symbol *name=f->featureValueQuick("name")->getSymbol();
				if (name->get()[0]=='L' &&
					name->get()[1]=='e' &&
					name->get()[2]=='a' &&
					name->get()[3]=='r' &&
					name->get()[4]=='n' &&
					name->get()[5]=='e' &&
					name->get()[6]=='r') {
					agent_names.Add(new Symbol(name));
				} /* if */ 
				if (name->get()[0]=='M' &&
					name->get()[1]=='o' &&
					name->get()[2]=='n' &&
					name->get()[3]=='i' &&
					name->get()[4]=='t' &&
					name->get()[5]=='o' &&
					name->get()[6]=='r') {
					monitor_names.Add(new Symbol(name));
				} /* if */ 
				
			} /* if */ 
		} /* while */ 
		pthread_mutex_unlock(&m_sensor_data_mutex);
		
		/* If there are no agents, then wait till there are some agents */ 
		if (agent_names.Length()==0) wait(100);

	}while(agent_names.Length()==0);	 

	write_debug_report("[Sync]: recognized %i learning agents.\n",agent_names.Length());

	for(iteration=0;iteration<m_n_iterations;iteration++) {
//	for(iteration=0;iteration<1;iteration++) {
		int *iteration_correct_answers;
		int *iteration_incorrect_answers;
		{
			int i;
			iteration_correct_answers=new int[m_times_to_send_external_testset];
			iteration_incorrect_answers=new int[m_times_to_send_external_testset];
			for(i=0;i<m_times_to_send_external_testset;i++) {
				iteration_correct_answers[i]=0;
				iteration_incorrect_answers[i]=0;
			} /* for */ 
		}

		write_debug_report("[Sync]: started iteration %i -----------------------------\n",iteration+1);
		write_debug_report("[Sync]: Time: %g sec.\n",(GetTickCount()-initial_time)/1000.0F);
		
		{
			char tmp[256];
			FeatureTerm *op;

			sprintf(tmp,"Iteration %i:",iteration+1);
			monitor_names.Rewind();
			while(monitor_names.Iterate(agent_name)) {
				op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
								   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
								   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
				enqueue_operator(op);
			} /* while */ 	
		}

		/* Generate folds: */ 
		test_status();
		{
			int j;
			int cases_per_fold=0;
			FeatureTerm *c;
			List<FeatureTerm> tmp;

			tmp.Copy(case_base);

			cases_per_fold=case_base.Length()/m_n_folds;

			for(fold=0;fold<m_n_folds-1;fold++) {
				folds[fold].Delete();
				for(j=0;j<cases_per_fold;j++) {
					c=tmp[m_random->IRandom(0,tmp.Length()-1)];
					tmp.DeleteElement(c);
					folds[fold].Add(c);
				} /* for */ 
			} /* for */ 
			folds[m_n_folds-1].Delete();
			while(!tmp.EmptyP()) folds[m_n_folds-1].Add(tmp.ExtractIni());
			write_debug_report("[Sync]: folds created.\n");
		}

		for(fold=0;fold<m_n_folds;fold++) {
//		for(fold=0;fold<1;fold++) {

			write_debug_report("[Sync]: started fold %i of iteration %i-----------------------------\n",fold+1,iteration+1);
			write_debug_report("[Sync]: Time: %g sec.\n",(GetTickCount()-initial_time)/1000.0F);
			
			/* Partition data-set in test and training set: */ 
			test_status();
			{
				int j;
				FeatureTerm *c;

				training_set.Delete();
				test_set.Delete();

				for(j=0;j<m_n_folds;j++) {
					if (j==fold) {
						folds[j].Rewind();
						while(folds[j].Iterate(c)) test_set.Add(new FeatureTerm(c));
					} else {
						folds[j].Rewind();
						while(folds[j].Iterate(c)) training_set.Add(new FeatureTerm(c));
					} /* if */  
				} /* for */ 
				test_set.Randomize();
				training_set.Randomize();
				write_debug_report("[Sync]: training set created: %i cases.\n",training_set.Length());
				write_debug_report("[Sync]: test set created: %i cases.\n",test_set.Length());
			}

			{
				/* Set the color of the agent to "starting fold": */ 
				FeatureTerm *op;
				op=FeatureTerm::fromStringNOOS("(define (color-operator) (r 0.4) (g 0.4) (b 1.0))",m_memory,m_ontology);
				enqueue_operator(op);
			}

			/* Distribute the training set: */ 
			test_status();
			{
				int i;
				FeatureTerm *c;
				FeatureTerm *op;
				AW_Message *m;
				char *str;
//				int total_to_distribute=0;
				int messages_to_wait=0;

				List <FeatureTerm> *distribution;

				distribution= new List<FeatureTerm>[agent_names.Length()];

				AW_NOOSExperimenterBrainCV::splitTrainingSet(distribution,&training_set,agent_names.Length(),m_percentage_to_distribute,m_desired_bias);

/*			
				total_to_distribute=int(training_set.Length()*m_percentage_to_distribute_as_initial_training);
				for(i=0;i<total_to_distribute;i++) {
					int k=m_random->IRandom(0,training_set.Length()-1);
					distribution[m_random->IRandom(0,agent_names.Length()-1)].Add(training_set[k]);
					training_set.DeletePosition(k);
				} // for 
*/			

				for(i=0;i<agent_names.Length();i++) {
					agent_name=agent_names[i];

					if (distribution[i].Length()>0) {
						int j;
						char *prefix="(define (learn-message) (case ";
						char *sufix=" ))";
						int len=1+strlen(prefix)+strlen(sufix);

						distribution[i].Rewind();
						while(distribution[i].Iterate(c)) {
							j=case_base.Position(c);
							len+=strlen(case_base_text[j])+1;
						} // while 

						str=new char[len];
						sprintf(str,prefix);
						distribution[i].Rewind();
						while(distribution[i].Iterate(c)) {
							j=case_base.Position(c);
							strcat(str,case_base_text[j]);
							strcat(str," ");
						} // while  
						strcat(str,sufix);

						distribution[i].Delete();
						messages_to_wait++;

						op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
										   "receiver",new FeatureTerm(0,
																	  new Symbol(agent_name),
																	  m_ontology),
										   "content",new FeatureTerm(0,
																	  new Symbol(str),
																	  m_ontology));
						delete []str;

						enqueue_operator(op);
						write_debug_report("[Sync]: cases sent to %s.\n",agent_name->get());
					} // if
				} // for  

				for(i=0;i<messages_to_wait;i++) {
					// Wait for the confirmation of the agent:  
					wait_message();
					m=get_message();
//					write_debug_report("[Sync]: received confirmation from %s [%i confirmations remaining]\n",m->sender->get(),agent_names.Length()-(i+1));
					delete m;
				} // for  

				delete []distribution;
			} 

			{
				/* Set the color of the agent to "waiting": */ 
				FeatureTerm *op;
				op=FeatureTerm::fromStringNOOS("(define (color-operator) (r 1.0) (g 1.0) (b 1.0))",m_memory,m_ontology);
				enqueue_operator(op);
			}

			/* Send the training set (one by one): */ 
			test_status();
			{
				int training_cases_sent=0;
				float remaining_for_test_set=0;
				float interval_between_test_sets=float(training_set.Length()/(m_times_to_send_external_testset-1));
				int current_test_set=0;
				Symbol *agent_name;
				FeatureTerm *c,*c2,*msg,*op;
				char *str;
				AW_Message *m;
				int *correct_answers;
				int *incorrect_answers;
				bool end=false;
				{
					int i;
					correct_answers=new int[m_times_to_send_external_testset];
					incorrect_answers=new int[m_times_to_send_external_testset];
					for(i=0;i<m_times_to_send_external_testset;i++) {
						correct_answers[i]=0;
						incorrect_answers[i]=0;
					} /* for */ 
				}


				training_set.Rewind();
				while(!end) {

					c=0;

					if (!training_set.Iterate(c) || (remaining_for_test_set<=0 && (current_test_set+1)<m_times_to_send_external_testset)) {

						// Request CB sizes:
						{
							char *str;
							int cb_size;
							List<Symbol> l;

							msg=new FeatureTerm((char *)0,m_ontology->get_sort("request-casebase-size"),0);
							str=msg->toStringNOOS(m_memory);
							delete msg;

							l.Instance(agent_names);
							l.Rewind();
							while(l.Iterate(agent_name)) {
								op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
												   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
												   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
								enqueue_operator(op);

								wait_message();
								m=get_message();

								sscanf(m->content->get(),"%i",&cb_size);
								average_cb_size[current_test_set]+=cb_size;
							} /* wihle */ 

							delete []str;
						}

						remaining_for_test_set+=interval_between_test_sets;

						// Send the test set!!
						write_debug_report("[Sync]: ---------------------------\n");
						write_debug_report("[Sync]: -  Sending the test set (%i) --\n",training_cases_sent);
						write_debug_report("[Sync]: ---------------------------\n");
						
						test_set.Rewind();
						while(test_set.Iterate(c2)) {

							/* Send the problem: */ 
							agent_name=agent_names[m_random->IRandom(0,agent_names.Length()-1)];
							msg=new FeatureTerm((char *)0,m_ontology->get_sort("request-test-prediction-message"),1,
												"problem",get_description(c2));
							if (m_test_collaboration_strategy->get()!=0) msg->defineFeatureValue("strategy",new FeatureTerm((Symbol *)0,new Symbol(m_test_collaboration_strategy),m_ontology));

							str=msg->toStringNOOS(m_memory);
							op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
											   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
											   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
							delete []str;
							delete msg;

							enqueue_operator(op);
							write_debug_report("[Sync]: test case sent to %s.\n",agent_name->get());


							/* Wait for the answer of the agent: */ 
							wait_message();
							m=get_message();
//							write_debug_report("[Sync]: received answer from %s\n",m->sender->get());

							/* Check whether the answer is correct: */ 
							{
								FeatureTerm *correct,*answer,*prediction=0;						
								char *s,*s2;

								correct=get_solution(c2);

								answer=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
								prediction=answer->featureValue("solution");

								if (prediction!=0) {
									s=correct->toStringNOOS(m_memory);
									s2=prediction->toStringNOOS(m_memory);
									write_debug_report("[Sync]: [%s][%s] %s -> %s \n",c2->getName()->get(),(*prediction==*correct ? "correct":"incorrect"),s,s2);
									delete []s;
									delete []s2;

									if (*prediction==*correct) {
										correct_answers[current_test_set]++;
									} else {
										incorrect_answers[current_test_set]++;
									} /* if */ 
									delete prediction;
								} else {
									s=correct->toStringNOOS(m_memory);
									write_debug_report("[Sync]: %s -> -\n",s);
									delete []s;
									incorrect_answers[current_test_set]++;
								} /* if */ 

								delete answer;
								delete correct;
							}

							/* Send the agent the correct solution, so that it can perform the retain process: */ 
							{
								msg=new FeatureTerm((char *)0,m_ontology->get_sort("solution-test-inform-message"),1,
													"solution",get_solution(c2));

								str=msg->toStringNOOS(m_memory);
								op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
												   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
												   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
								delete []str;
								delete msg;

								enqueue_operator(op);
							}

							/* Wait for the answer of the agent: */ 
							wait_message();
							m=get_message();
//							write_debug_report("[Sync]: received answer from %s\n",m->sender->get());
							write_debug_report("[Sync]: ---- next test problem ---- \n\n\n",m->sender->get());

							delete m;
						} /* while */ 

						write_debug_report("[Sync]: --------------------\n");
						write_debug_report("[Sync]: -  Test set sent  --\n");
						write_debug_report("[Sync]: --------------------\n\n\n");

						current_test_set++;
					} /* if */ 

					if (c!=0) {
						// Send training case:
						training_cases_sent++;
						remaining_for_test_set--;

						/* Send the problem: */ 
						agent_name=agent_names[m_random->IRandom(0,agent_names.Length()-1)];
						msg=new FeatureTerm((char *)0,m_ontology->get_sort("request-prediction-message"),1,
											"problem",get_description(c));
						if (m_collaboration_strategy->get()!=0) msg->defineFeatureValue("strategy",new FeatureTerm((Symbol *)0,new Symbol(m_collaboration_strategy),m_ontology));

						str=msg->toStringNOOS(m_memory);
						op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
										   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
										   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
						delete []str;
						delete msg;

						enqueue_operator(op);
						write_debug_report("[Sync]: train case sent to %s.\n",agent_name->get());


						/* Wait for the answer of the agent: */ 
						wait_message();
						m=get_message();
//						write_debug_report("[Sync]: received answer from %s\n",m->sender->get());

						/* Check whether the answer is correct: */ 
						{
							FeatureTerm *correct,*answer,*prediction=0;						
							char *s,*s2;

							correct=get_solution(c);

							answer=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
							prediction=answer->featureValue("solution");

							if (prediction!=0) {
								s=correct->toStringNOOS(m_memory);
								s2=prediction->toStringNOOS(m_memory);
								write_debug_report("[Sync]: [%s][%s] %s -> %s \n",c->getName()->get(),(*prediction==*correct ? "correct":"incorrect"),s,s2);
								delete []s;
								delete []s2;
							} else {
								s=correct->toStringNOOS(m_memory);
								write_debug_report("[Sync]: %s -> -\n",s);
								delete []s;
							} /* if */ 

							delete answer;
							delete correct;
						}

						/* Send the agent the correct solution, so that it can perform the retain process: */ 
						{
							msg=new FeatureTerm((char *)0,m_ontology->get_sort("solution-inform-message"),1,
												"solution",get_solution(c));

							str=msg->toStringNOOS(m_memory);
							op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
											   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
											   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
							delete []str;
							delete msg;

							enqueue_operator(op);
						}

						/* Wait for the answer of the agent: */ 
						wait_message();
						m=get_message();
//						write_debug_report("[Sync]: received answer from %s\n",m->sender->get());
						write_debug_report("[Sync]: ---- next problem ---- \n\n\n",m->sender->get());

						delete m;
					} else {
						end=true;
					} /* if */ 
				} /* while */ 

				//Send messages to MONITOR agent:
				{
					int i;
					char tmp[256];
					FeatureTerm *op;
					float *excel_tmp=new float[m_times_to_send_external_testset];

					sprintf(tmp,"Fold %i:",fold+1);
					write_debug_report("[Sync]: %s\n",tmp);

					monitor_names.Rewind();
					while(monitor_names.Iterate(agent_name)) {
						op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
										   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
										   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
						enqueue_operator(op);
					} /* while */ 					 
					for(i=0;i<m_times_to_send_external_testset;i++) {
						char tmp[256];
						float v=(correct_answers[i]+incorrect_answers[i]==0 ? 0:float(100*correct_answers[i])/float(correct_answers[i]+incorrect_answers[i]));
						sprintf(tmp,"%i/%i (%g%%)",
									correct_answers[i],correct_answers[i]+incorrect_answers[i],
									v);
						excel_tmp[i]=v;
						write_debug_report("[Sync]: %s\n",tmp);

						monitor_names.Rewind();
						while(monitor_names.Iterate(agent_name)) {
							op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
											   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
											   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
							enqueue_operator(op);
						} /* while */ 					 
					} /* for */ 

					values_for_excel.Add(excel_tmp);
				}
				{
					int i;
					for(i=0;i<m_times_to_send_external_testset;i++) {
						iteration_correct_answers[i]+=correct_answers[i];
						iteration_incorrect_answers[i]+=incorrect_answers[i];
					}
				}

				delete []correct_answers;
				delete []incorrect_answers;
			}

			/* Clear the case bases of the agents: */ 
			{
				int i;
				FeatureTerm *op;
				FeatureTerm *msg;
				Symbol *agent_name;
				AW_Message *m;
				char *str;

				for(i=0;i<agent_names.Length();i++) {
					agent_name=agent_names[i];

					msg=new FeatureTerm((char *)0,m_ontology->get_sort("forget-message"),0);
					str=msg->toStringNOOS(m_memory);
					op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
									   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
									   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
					delete str;
					delete msg;

					enqueue_operator(op);

					write_debug_report("[Sync]: forget message sent to %s.\n",agent_name->get());
				} /* for */ 

				for(i=0;i<agent_names.Length();i++) {
					/* Wait for the confirmation of the agent: */ 
					wait_message();
					m=get_message();
//					write_debug_report("[Sync]: received confirmation from %s [%i confirmations remaining]\n",m->sender->get(),agent_names.Length()-(i+1));
					delete m;
				} /* for */ 
			}
	
			wait(1);
		} /* for */ 

		{
			//Send messages to MONITOR agent:
			{
				int i;
				char tmp[256];
				FeatureTerm *op;
				sprintf(tmp,"Iteration %i:",iteration+1);
				write_debug_report("[Sync]: %s\n",tmp);

				monitor_names.Rewind();
				while(monitor_names.Iterate(agent_name)) {
					op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
									   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
									   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
					enqueue_operator(op);
				} /* while */ 					 
				for(i=0;i<m_times_to_send_external_testset;i++) {
					char tmp[256];
					sprintf(tmp,"%i/%i (%g%%)",
								iteration_correct_answers[i],iteration_correct_answers[i]+iteration_incorrect_answers[i],
								(iteration_correct_answers[i]+iteration_incorrect_answers[i]==0 ? 0:float(100*iteration_correct_answers[i])/float(iteration_correct_answers[i]+iteration_incorrect_answers[i])));
					write_debug_report("[Sync]: %s\n",tmp);

					monitor_names.Rewind();
					while(monitor_names.Iterate(agent_name)) {
						op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
										   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
										   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
						enqueue_operator(op);
					} /* while */ 					 
				} /* for */ 
			}


			{
				int i;
				for(i=0;i<m_times_to_send_external_testset;i++) {
					total_correct_answers[i]+=iteration_correct_answers[i];
					total_incorrect_answers[i]+=iteration_incorrect_answers[i];
				}
			}
			delete []iteration_correct_answers;
			delete []iteration_incorrect_answers;
		}
	} /* for */ 

	//Send messages to MONITOR agent:
	{
		int i;
		char tmp[256];
		FeatureTerm *op;
		sprintf(tmp,"Total Accuracy:");
		write_debug_report("[Sync]: %s\n",tmp);

		monitor_names.Rewind();
		while(monitor_names.Iterate(agent_name)) {
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
			enqueue_operator(op);
		} /* while */ 					 
		for(i=0;i<m_times_to_send_external_testset;i++) {
			char tmp[256];
			sprintf(tmp,"%i/%i (%g%%)",
						total_correct_answers[i],total_correct_answers[i]+total_incorrect_answers[i],
						(total_correct_answers[i]+total_incorrect_answers[i]==0 ? 0:float(100*total_correct_answers[i])/float(total_correct_answers[i]+total_incorrect_answers[i])));
			write_debug_report("[Sync]: %s\n",tmp);

			monitor_names.Rewind();
			while(monitor_names.Iterate(agent_name)) {
				op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
								   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
								   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
				enqueue_operator(op);
			} /* while */ 					 
		} /* for */ 

		write_debug_report("[Sync]: Average CB size\n");
		for(i=0;i<m_times_to_send_external_testset;i++) {
			char tmp[256];
			sprintf(tmp,"%g",float(average_cb_size[i])/(m_n_folds*m_n_iterations*agent_names.Length()));
			write_debug_report("[Sync]: %s\n",tmp);
		} /* for */ 

		write_debug_report("[Sync]: experiments finished.\n");
		write_debug_report("[Sync]: Time: %g sec.\n",(GetTickCount()-initial_time)/1000.0F);

		{
			int i;
			float *fp;
			write_debug_report("[Sync]: EXCEL READABLE RESULTS:\n");

			values_for_excel.Rewind();
			while(values_for_excel.Iterate(fp)) {
				for(i=0;i<m_times_to_send_external_testset;i++) {
					write_debug_report("%g ",fp[i]);
				} // for
				write_debug_report("\n");
			} // while 
		}


	}


	delete []folds;
	delete []total_correct_answers;
	delete []total_incorrect_answers;
	delete []average_cb_size;

	{
		/* Kill Experimenter agent: */ 
		FeatureTerm *op;
		op=FeatureTerm::fromStringNOOS("(define (suicide-operator))",m_memory,m_ontology);
		enqueue_operator(op);
	}

} /* AW_NOOSExperimenterBrainCVContinuous::thread */ 

